#include "disp_driver.h"
#include <stdio.h>

extern configuration config;

lcd_init_cmd_t st7789_init_cmds[] = {
    {0x01, {0}, 0x80, 120},
    /* Sleep Out */
    {0x11, {0}, 0x80, 120},
    /* Memory Data Access Control, MX=MV=1, MY=ML=MH=0, RGB=0 */
    {0x36, {0x00}, 1},
    /* Interface Pixel Format, 16bits/pixel for RGB/MCU interface */
    {0x3A, {0x05}, 1},
#if 0
      {0x30, {0x00,0x50,0x01,0x3F}, 4},
      {0x12, {0x00}, 0},
#endif
    /* Porch Setting */
    {0xB2, {0x0c, 0x0c, 0x00, 0x33, 0x33}, 5},
    /* Gate Control, Vgh=13.65V, Vgl=-10.43V */
    {0xB7, {0x35}, 1},
    /* VCOM Setting, VCOM=1.35V */
    {0xBB, {0x32}, 1},
    // /* LCM Control, XOR: BGR, MX, MH */
    // {0xC0, {0x2C}, 1},
    /* VDV and VRH Command Enable, enable=1 */
    {0xC2, {0x01, 0xFF}, 2},
    /* VRH Set, Vap=4.4+... */
    {0xC3, {0x15}, 1},
    /* VDV Set, VDV=0 */
    {0xC4, {0x20}, 1},
    /* Frame Rate Control, 60Hz, inversion=0 */
    {0xC6, {0x0F}, 1},
    /* Power Control 1, AVDD=6.8V, AVCL=-4.8V, VDDS=2.3V */
    {0xD0, {0xA4, 0xA1}, 1},
    /* Positive Voltage Gamma Control */
    {0xE0,
     {0xD0, 0x08, 0x0E, 0x09, 0x09, 0x05, 0x31, 0x33, 0x48, 0x17, 0x14, 0x15,
      0x31, 0x34},
     14},
    /* Negative Voltage Gamma Control */
    {0xE1,
     {0xD0, 0x08, 0x0E, 0x09, 0x09, 0x15, 0x31, 0x33, 0x48, 0x17, 0x14, 0x15,
      0x31, 0x34},
     14},
    /* Display On */
    {0x21, {0}, 0},
    {0x29, {0}, 0},
    {0, {0}, 0xff}};

extern disp_driver_api api;
void st7789_api_init(void){
    api.disp_init_cmd = st7789_init_cmds;
    api.disp_set_window  = st7789_set_window;
    api.disp_set_orientation = st7789_set_orientation;
}
/* The ST7789 display controller can drive 320*240 displays, when using a
 * 240*240 display there's a gap of 80px, we need to edit the coordinates to
 * take into account that gap, this is not necessary in all orientations. */
void st7789_set_window(lv_disp_drv_t *drv, const lv_area_t *area) {
    uint8_t data[4] = {0};

    uint16_t offsetx1 = area->x1;
    uint16_t offsetx2 = area->x2;
    uint16_t offsety1 = area->y1;
    uint16_t offsety2 = area->y2;

    offsetx1 += config.offset_x;
    offsetx2 += config.offset_x;
    offsety1 += config.offset_y;
    offsety2 += config.offset_y;

    /*Column addresses*/
    disp_send_cmd(ST7789_CASET);
    data[0] = (offsetx1 >> 8) & 0xFF;
    data[1] = offsetx1 & 0xFF;
    data[2] = (offsetx2 >> 8) & 0xFF;
    data[3] = offsetx2 & 0xFF;
    disp_send_data(data, 4);

    /*Page addresses*/
    disp_send_cmd(ST7789_RASET);
    data[0] = (offsety1 >> 8) & 0xFF;
    data[1] = offsety1 & 0xFF;
    data[2] = (offsety2 >> 8) & 0xFF;
    data[3] = offsety2 & 0xFF;
    disp_send_data(data, 4);

    /*Memory write*/
    disp_send_cmd(ST7789_RAMWR);
}

void st7789_set_orientation(uint8_t orientation) {
    const char *orientation_str[] = {"PORTRAIT", "PORTRAIT_INVERTED",
                                     "LANDSCAPE", "LANDSCAPE_INVERTED"};

    printf("Display orientation: %s\n", orientation_str[orientation]);

    uint8_t data[] = {0xC0, 0x00, 0x60, 0xA0};

    disp_send_cmd(ST7789_MADCTL);
    disp_send_data((void *)&data[orientation], 1);
}